var cls=require("./../lib/class"),Ball=require("./ball"),Team=require("./team"),Field=require("./field"),Utils=require("./../utils"),_=require("underscore"),Log=require("log"),Types=require("../../../shared/js/gametypes");
module.exports=Match=Class.extend({init:function(a,b){this.id=a||100;this.server=b;this.initTime=Date.now();this.isKnockoutStage=!1;this.ongoingMatch=null;this.gameState=Types.Gamestates.INIT;this.timeState=[Config.StateTime.INT,Config.StateTime.REGISTER,Config.StateTime.READY,Config.StateTime.CHOOSE_FIRST_PLAYER,Config.StateTime.SETBOARD,Config.StateTime.TURN_TIME,Config.StateTime.ENDSET,Config.StateTime.RESET,Config.StateTime.ENDGAME];this.frameCount=0;this.currentSet=1;this.totalSet=50;this.teamBSetupBoardResult=
this.teamASetupBoardResult=Types.SetupResult.SUCCESS;this.turnNumber=this.teamBWin=this.teamAWin=0;this.players=[];this.playingUser=[];this.teamBDestroyedShipType=this.teamADestroyedShipType=this.playerTurn=0;this.boardA=[];this.boardB=[];this.currentBoardA=[];this.currentBoardB=[];for(var d=0;100>d;d++)this.boardA[d]=0,this.boardB[d]=0,this.currentBoardA[d]=0,this.currentBoardB[d]=0;this.hasMatchGoing=!1;this.prevLogData=[];this.readyCount=0;this.startCount=!1;this.secondSentPlayerID=this.firstSentPlayerID=
this.sentFirstPlayCount=this.firstReadyID=this.playerCount=0;this.messageFirst=[];this.messageSecond=[];this.firstSentBoardID=this.sentBoardCount=0;this.isNeedUpdate=!1;this.turnPost=[-1,-1];this.totalHitBCount=this.totalHitACount=0;this.isTurned=!1;this.currentTime=new Date;this.lastTime=new Date;this.isBoardBSetted=this.isBoardASetted=this.isStarted=this.isEndset=this.isResetedGame=!1},update:function(){try{var a=this;this.frameCount++;switch(a.gameState){case Types.Gamestates.INIT:a.startCount=
!0;break;case Types.Gamestates.REGISTER:2>a.playerCount&&(log.debug("A player disconnected"),a.gameState=Types.Gamestates.ENDGAME,a.gameWinner=1);a.startCount=2<=a.readyCount?!0:!1;break;case Types.Gamestates.READY:a.startCount=!0;break;case Types.Gamestates.CHOOSE_FIRST_PLAYER:if(2<=this.sentFirstPlayCount&&0==this.playerTurn){for(var b=0;3>b;)if(0==this.messageFirst[b]&&1==this.messageSecond[b]){this.playerTurn=this.players[0];break}else if(1==this.messageFirst[b]&&2==this.messageSecond[b]){this.playerTurn=
this.players[0];break}else if(2==this.messageFirst[b]&&0==this.messageSecond[b]){this.playerTurn=this.players[0];break}else if(this.messageFirst[b]==this.messageSecond[b])b++;else{this.playerTurn=this.players[1];break}0==this.playerTurn&&(this.playerTurn=0==(100*Math.random()<<0)%2?this.players[0]:this.players[1]);this.turnTime=Config.StateTime.TURN_TIME}a.startCount=!0;break;case Types.Gamestates.SETBOARD:a.startCount=!0;break;case Types.Gamestates.GAMEPLAY:if(!this.isTurned)if(this.playerTurn==
this.players[0]){if(0<=this.turnPost[0]&&10>this.turnPost[0]&&0<=this.turnPost[1]&&10>this.turnPost[1]){var d=10*this.turnPost[1]+this.turnPost[0];this.currentBoardB[d]==Types.BoardStatus.EMPTY&&(0!=this.boardB[d]?(this.currentBoardB[d]=Types.BoardStatus.HITTED,this.totalHitBCount++,this.teamBDestroyedShipType=this.getDestroyedShipType(d,this.currentBoardB,this.boardB)):(this.currentBoardB[d]=Types.BoardStatus.MISSED,this.teamBDestroyedShipType=0));this.isTurned=!0}}else 0<=this.turnPost[0]&&10>this.turnPost[0]&&
(0<=this.turnPost[1]&&10>this.turnPost[1])&&(d=10*this.turnPost[1]+this.turnPost[0],this.currentBoardA[d]==Types.BoardStatus.EMPTY&&(0!=this.boardA[d]?(this.currentBoardA[d]=Types.BoardStatus.HITTED,this.totalHitACount++,this.teamADestroyedShipType=this.getDestroyedShipType(d,this.currentBoardA,this.boardA)):(this.currentBoardA[d]=Types.BoardStatus.MISSED,this.teamADestroyedShipType=0)),this.isTurned=!0);a.startCount=!0;break;case Types.Gamestates.ENDSET:this.isEndset||(log.info("A Win: "+this.teamAWin),
log.info("B Win: "+this.teamBWin),this.isEndset=!0);a.startCount=!0;break;case Types.Gamestates.RESET:!1==this.isResetedGame&&(this.isResetedGame=!0,this.isEndset=!1,this.resetGame(),this.currentSet++),a.startCount=!0}if(this.startCount)switch(this.gameState){case Types.Gamestates.GAMEPLAY:this.lastTime=new Date;var c=this.lastTime-this.currentTime;100<c&&(this.turnTime--,this.currentTime=this.lastTime);0>this.turnTime&&(this.turnTime=Config.StateTime.TURN_TIME,this.playerTurn=this.playerTurn==this.players[0]?
this.players[1]:this.players[0],17==this.totalHitACount&&(this.teamBWin++,this.gameState=Types.Gamestates.ENDSET),17==this.totalHitBCount&&(this.teamAWin++,this.gameState=Types.Gamestates.ENDSET),200<this.turnNumber&&(this.gameState=Types.Gamestates.ENDSET),this.turnNumber++,this.turnPost[0]=-1,this.turnPost[1]=-1,this.isTurned=!1);break;case Types.Gamestates.ENDSET:this.lastTime=new Date;c=this.lastTime-this.currentTime;1E3<c&&(this.timeState[this.gameState]--,this.currentTime=this.lastTime);0>this.timeState[this.gameState]&&
(this.timeState[this.gameState]=Config.StateTime.ENDSET,this.isResetedGame=!1,this.gameState=Types.Gamestates.RESET);break;case Types.Gamestates.SETBOARD:this.lastTime=new Date;c=this.lastTime-this.currentTime;1E3<c&&(this.timeState[this.gameState]--,this.currentTime=this.lastTime);0>this.timeState[this.gameState]&&(2<=this.sentBoardCount?this.gameState++:(this.timeState[this.gameState]=Config.StateTime.SETBOARD,this.isBoardASetted&&this.teamAWin++,this.isBoardBSetted&&this.teamBWin++,this.isResetedGame=
!1,this.gameState=Types.Gamestates.RESET));break;case Types.Gamestates.RESET:this.lastTime=new Date;c=this.lastTime-this.currentTime;1E3<c&&(this.timeState[this.gameState]--,this.currentTime=this.lastTime);0>this.timeState[this.gameState]&&(this.timeState[this.gameState]=Config.StateTime.RESET,this.gameState=this.isKnockoutStage?2<this.teamAWin-this.teamBWin||2<this.teamBWin-this.teamAWin?Types.Gamestates.ENDGAME:Types.Gamestates.SETBOARD:this.currentSet>this.totalSet?Types.Gamestates.ENDGAME:Types.Gamestates.SETBOARD);
break;case Types.Gamestates.ENDGAME:this.lastTime=new Date;c=this.lastTime-this.currentTime;1E3<c&&(this.timeState[this.gameState]--,this.currentTime=this.lastTime);if(0>this.timeState[this.gameState]){log.info("--- Kill process. ---");this.hasMatchGoing=!1;this.ongoingMatch=null;this.isStarted=a.startCount=!1;for(b=0;b<a.playerCount;b++)a.server.closeClientConnection(a.players[b]);this.teamBWin=this.teamAWin=0;this.currentSet=1;a.removePlayer(a.players[0]);a.removePlayer(a.players[1]);this.playerCount=
0;this.gameState=Types.Gamestates.INIT;a.resetGame()}break;case Types.Gamestates.INIT:this.lastTime=new Date;c=this.lastTime-this.currentTime;1E3<c&&(this.timeState[this.gameState]--,this.currentTime=this.lastTime);0>this.timeState[this.gameState]&&(2>a.playerCount?(this.timeState[this.gameState]=Config.StateTime.INT,this.gameState=Types.Gamestates.RESET):this.gameState++);break;default:if(this.lastTime=new Date,c=this.lastTime-this.currentTime,1E3<c&&(this.timeState[this.gameState]--,this.currentTime=
this.lastTime),0>this.timeState[this.gameState])switch(this.gameState){default:this.gameState<Types.Gamestates.ENDGAME&&this.gameState++}}}catch(f){a.dumpError(f)}},resetGame:function(){this.timeState=[Config.StateTime.INT,Config.StateTime.REGISTER,Config.StateTime.READY,Config.StateTime.CHOOSE_FIRST_PLAYER,Config.StateTime.SETBOARD,Config.StateTime.TURN_TIME,Config.StateTime.ENDSET,Config.StateTime.RESET,Config.StateTime.ENDGAME];this.frameCount=0;this.isNeedUpdate=!1;this.turnPost=[-1,-1];for(var a=
this.totalHitBCount=this.totalHitACount=0;100>a;a++)this.boardA[a]=0,this.boardB[a]=0,this.currentBoardA[a]=0,this.currentBoardB[a]=0;this.turnNumber=0;this.teamBSetupBoardResult=this.teamASetupBoardResult=Types.SetupResult.SUCCESS;this.firstSentBoardID=this.sentBoardCount=this.teamBDestroyedShipType=this.teamADestroyedShipType=0;this.isBoardBSetted=this.isBoardASetted=!1},addPlayer:function(a){2>this.playerCount&&(this.players.push(a),this.playerCount++,log.info("-------------ADD PLAYER-------------"+
this.playerCount))},removePlayer:function(a){this.players=_.reject(this.players,function(b){return b===a});this.playerCount--},handleGameAction:function(a,b){var d=b.length;log.info("MESSAGE: "+d);for(var c=0;c<d-1;)switch(b[c]){case Types.Gameactions.REGISTER:log.info("ACTION: REGISTER");if(this.gameState!=Types.Gamestates.REGISTER){c+=1;break}log.debug("receive register "+b[1]);0==this.firstReadyID&&(0<b[1]&&5>b[1])&&(this.readyCount++,this.firstReadyID=a.id,this.players[0]=a.id);0!=this.firstReadyID&&
this.firstReadyID!=a.id&&(2>this.readyCount&&0<b[1]&&5>b[1])&&(this.readyCount++,this.players[1]=a.id);c+=1;log.info("***************** READY COUNT  "+this.readyCount+" "+a.id);break;case Types.Gameactions.CHOOSE_FIRST_PLAYER:0==this.sentFirstPlayCount?(this.sentFirstPlayCount++,this.firstSentPlayerID=a.id,a.id==this.players[0]?this.messageFirst=b.slice(c,c+3):this.messageSecond=b.slice(c,c+3)):1==this.sentFirstPlayCount&&this.firstSentPlayerID!=a.id&&(this.sentFirstPlayCount++,this.secondSentPlayerID=
a.id,a.id==this.players[0]?this.messageFirst=b.slice(c,c+3):this.messageSecond=b.slice(c,c+3));c+=3;break;case Types.Gameactions.SETBOARD:log.info("ACTION: SETBOARD");c++;0==this.firstSentBoardID?(this.firstSentBoardID=a.id,this.sentBoardCount++,a.id==this.players[0]?(this.boardA=b.slice(c,c+100),this.isBoardASetted=!0,log.info("BOAR: A: "+this.boardA)):(this.boardB=b.slice(c,c+100),isBoardBSetted=!0,log.info("BOAR: B: "+this.boardB))):this.firstSentBoardID!=a.id&&(this.sentBoardCount++,a.id==this.players[0]?
(this.boardA=b.slice(c,c+100),log.info("BOAR: A: "+this.boardA),this.isBoardASetted=!0):(this.boardB=b.slice(c,c+100),log.info("BOAR: B: "+this.boardB),this.isBoardBSetted=!0));c+=100;break;case Types.Gameactions.TURN:this.playerTurn==a.id&&(this.playerTurn==this.players[0]?log.info("ACTION: TURN PLAYER 1"):log.info("ACTION: TURN PLAYER 2"),log.info("Turn message: "+b.slice(1,3)),this.turnPost=b.slice(1,3),this.isNeedUpdate=!0),c+=5}},getSetupBoardResult:function(a){for(var b,d,c,f,e=f=c=d=b=0;100>
e;e++)switch(a[e]){case 2:b++;break;case 3:d++;break;case 4:c++;break;case 5:f++}if(2!=b||6!=d||4!=c||5!=f)return log.info("!!! setup board ERROR !!!"),Types.SetupResult.ERROR;for(e=0;97>e;e++)if(8>e%10&&9!=(e+2)%10&&3==a[e]&&3==a[e+1]&&3==a[e+2]&&3==a[e+3])return log.info("!!! setup board ERROR !!!"),Types.SetupResult.ERROR;for(b=0;10>b;b++)for(d=0;10>d;d++){c=!0;for(e=0;4>e;e++)if(3!=a[10*(d+e)+b]){c=!1;break}if(!0==c)return log.info("!!! setup board ERROR !!!"),Types.SetupResult.ERROR}for(e=c=
0;100>e;e++){if(0<a[e]&&0<c&&a[e]!=c)return log.info("!!! setup board ERROR !!!"),Types.SetupResult.ERROR;c=a[e]}for(b=c=0;10>b;b++)for(d=0;10>d;d++){e=10*d+b;if(0<a[e]&&0<c&&a[e]!=c)return log.info("!!! setup board ERROR !!!"),Types.SetupResult.ERROR;c=a[e]}log.info("setup board success!");return Types.SetupResult.SUCCESS},getDestroyedShipType:function(a,b,d){d=d[a];if(0==d)return 0;var c=0,f=a%10;0<=f-d+1?f=d-1:f++;var e=a-f;0>e&&(e=0);var g=0,g=9>=f+d-1?a+d-1:Math.floor(a/10)+9;99<g&&(g=99);for(f=
e;f<=g;f++)if(b[f]==Types.BoardStatus.HITTED){if(c++,c==d){for(c=0;c<d;c++)b[f-c]=d;return d}}else c=0;c=0;g=a%10;f=Math.floor(a/10)-d+1;0>f&&(f=0);a=Math.floor(a/10)+d-1;for(9<a&&(a=9);f<=a;f++)if(e=10*f+g,b[e]==Types.BoardStatus.HITTED){if(c++,c==d){for(c=0;c<d;c++)b[e-10*c]=d;return d}}else c=0;return 0},_getData:function(){for(var a=[this.gameState,this.timeState[this.gameState],this.frameCount,this.currentSet,this.totalSet,this.teamASetupBoardResult,this.teamBSetupBoardResult,this.teamAWin,this.teamBWin,
this.turnNumber,this.teamADestroyedShipType,this.teamBDestroyedShipType,this.players[0],this.players[1],this.playerTurn,this.turnPost[0],this.turnPost[1]],b=0;100>b;b++)a.push(this.currentBoardA[b]);for(b=0;100>b;b++)a.push(this.currentBoardB[b]);for(b=0;100>b;b++)a.push(this.boardA[b]);for(b=0;100>b;b++)a.push(this.boardB[b]);a.push(this.messageFirst[0]);a.push(this.messageFirst[1]);a.push(this.messageFirst[2]);a.push(this.messageSecond[0]);a.push(this.messageSecond[1]);a.push(this.messageSecond[2]);
return a},getData:function(){return this._getData()},getLog:function(){for(var a=[Types.Messages.UPDATE,this.gameState,this.timeState[this.gameState],this.frameCount,this.currentSet,this.totalSet,this.teamASetupBoardResult,this.teamBSetupBoardResult,this.teamAWin,this.teamBWin,this.turnNumber,this.teamADestroyedShipType,this.teamBDestroyedShipType,this.players[0],this.players[1],this.playerTurn,this.turnPost[0],this.turnPost[1]],b=0;100>b;b++)a.push(this.currentBoardA[b]);for(b=0;100>b;b++)a.push(this.currentBoardB[b]);
for(b=0;100>b;b++)a.push(this.boardA[b]);for(b=0;100>b;b++)a.push(this.boardB[b]);a.push(this.messageFirst[0]);a.push(this.messageFirst[1]);a.push(this.messageFirst[2]);a.push(this.messageSecond[0]);a.push(this.messageSecond[1]);a.push(this.messageSecond[2]);var d=[];if(0==this.prevLogData.length)d=a;else for(b=0;b<a.length;b++)this.prevLogData[b]!=a[b]&&(d[b]=a[b]);this.prevLogData=a;return d},dumpError:function(a){"object"===typeof a?(a.message&&console.log("\nMessage: "+a.message),a.stack&&(console.log("\nStacktrace:"),
console.log("===================="),console.log(a.stack))):console.log("dumpError :: argument is not an object")}});
